<?php
/**
 * URL处理类
 *
 * ============================================================================
 * 版权所有: (c) 2009-2011，<UEShop Inc>，并保留所有权利。
 * 网站地址: http://www.ueshop.cn
 * ----------------------------------------------------------------------------
 * 这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和使用；
 * 不允许对程序代码以任何形式任何目的的再发布。
 * ============================================================================
 * @author cmpan
 * @copyright   Copyright (c) 2009-2011 UEShop Inc. (http://www.ueshop.cn)
 * @license     http://www.ueshop.cn/1_0.txt
 */
class UE_Url_Exception extends UE_Exception {}

class UE_Url {	
	private static $_rules = array(
	    'item'           => 'info/show/item',
	    'list'           => 'info/show/list',
	    'productitem'    => 'product/show/item',
	    'productlist'    => 'product/show/list',
	    'attachment'     => 'system/uploader/load',
	    'thumb'          => 'system/uploader/thumb',
	);

    /**
	 * 构造一个url
	 * 根据系统配置返回三种形式的url,本别为
	 * 返回的url没有进行url编码,如需url编码请注意
	 * 1、$baseUrl?ctl=xx&act=xx&id=xx
	 * 2、$baseUrl?$ctl/$act/$id          (clear)
	 * 3、$baseUrl$ctl/$act/$id           (当UE_Config::get('rewrite') == 1)
	 *
	 * @param string $url  格式: app/ctl/act/id
	 * @return string
	 */
	public static function make($url, $allowClearUrl = true, $allowRewrite = true) {
		// 特殊字符实体化
		$url = str_replace(array('"', '<', '>'), array('&quot;', '&lt;', '&gt;'), trim($url, '/'));
		
		// 锚处理
		$anchor = '';
		if(false !== $pos = strpos($url, '#')) {
			$anchor = substr($url, $pos);
			$url = substr($url, 0, $pos);
		}
		
		// 生成Rewrite的URL
		$isRewrite = UE_Config::get('rewrite');
		
		if($allowRewrite && $isRewrite) {			
			// 替换成更简短的URL
			$urlSplit = explode('/', $url);			
			if (count($urlSplit) >= 3) {
				$actionPath = "{$urlSplit[0]}/{$urlSplit[1]}/{$urlSplit[2]}";
				$tag = array_search($actionPath, self::$_rules);
				if ($tag) {
					$url = $tag . ltrimStr($url, $actionPath);
				}
			}
			// end 替换成更简短的URL
			// 添加虚拟静态后缀			
			if (UE_Config::get('encode_url')) {
				$url = 'q_'.UE_Encoder::encode($url);
			}
			
			$url .= UE_Config::get('rewrite_ext');
		} else {
			if (!$allowClearUrl || !UE_Config::get('clean_url')) {						
				
				// 传统风格URL
				$paramsPair = array();
				parse_str($url, $params);
				
				if ($params) {
					$arr = array();
					$actionString = key($params);
					
					if (false !== strpos($actionString, '/')) {
						unset($params[$actionString]);
						
						if ($params) {
							foreach ($params as $key => $val) {
								$paramsPair[] = "$key=$val";
							}
						}
						
					    $arr = explode('/', $actionString);
					}
				}
				
				$paramsPair[] = empty($arr['0']) ? "app=".UE_Config::get('default_app') : "app={$arr['0']}";
				$paramsPair[] = empty($arr['1']) ? "ctl=".UE_Config::get('default_ctl') : "ctl={$arr['1']}";
				$paramsPair[] = empty($arr['2']) ? "act=".UE_Config::get('default_act') : "act={$arr['2']}";				
				empty($arr['3']) || $paramsPair[] = "id={$arr['3']}"; // id不是必须的
				
				if(isset($arr[4])) {
					for($i = 5; $i <= count($arr); $i += 2) {
						$paramsPair[] = $arr[$i-1] . '=' . (isset($arr[$i]) ? $arr[$i] : '');
					}
				}
				
				$url = implode('&', $paramsPair);			
				
			} 
			
			if (UE_Config::get('encode_url')) {
				$url = 'q='.UE_Encoder::encode($url);
			}
			
			$url = basename(PHP_SELF). '?'.$url;
		}
		
		
		
		// 本地化语言变量&locale=zh_CN|zh_TW|en_US|en_UK...
		// 默认使用UE_Config::get('locale')设置的语言
		if ((false === strpos($url, '/locale/') && false === strpos($url, '&locale=')) 
		  && UE_Config::get('locale') != UE_Lang::getLocale()) {
			$url .= (($allowRewrite && $isRewrite && false === strpos($url, '?')) ? '?' : '&' );
			$url .= 'locale='.UE_Lang::getLocale();
		}		
				
		// 恢复锚
		$url .= $anchor;
		
		if (UE_Config::get('full_url')) {
			$url = UE::site() . UE::context() . $url;
		}
				
		return $url;
	}

	/**
	 * 添加映射项
	 * 在parseUrl被调用之前调用才有效
	 * 添加的规则会覆盖相同的旧规则
	 * 
	 * @$key string 映射标识（前缀）
	 * @$value string 对应的参数
	 */
	public static function addRule($key, $value) {		
		self::$_rules[$key] =  $value;
		return true;
	}
		
	/**
	 * 把url请求标识转化成数组
	 *
	 * @param string $url
	 * @return array
	 */
	public static function parse($url) {
		static $parseHistory;
		
		if (isset($parseHistory[md5($url)])) {
			return $parseHistory[md5($url)];
		}
		
		// 去掉锚
		if(false !== $pos = strpos($url, '#')) {
			$url = substr($url, 0, $pos);
		}
		
		$param = array();
		$queryString = '';
		
		$defApp =  UE_Config::get('default_app');
		$defCtl =  UE_Config::get('default_ctl');
		$defAct =  UE_Config::get('default_act');
		$defId  =  UE_Config::get('default_id');
		
		// 可能的url
		// 1. {$ctx}$app/$ctl/$act/$id[/xx/$xx?yy=$yy]
		// 2. {$ctx}index.php?$app/$ctl/$act/$id[/xx/$xx?yy=$yy]
		// 3. {$ctx}index.php?app=$app&ctl=$ctl&act=$act[&....]		
		// 因为有些服务器POST的时候不能识别{$ctx}?app=$app&ctl=$ctl&act=$act[&....]的URL，
		// 因此系统在非Rewrite的情况下不用{$ctx}?xxx形式的URL
		// 找到URL里没有index.php则当成是Rewrite的URL
		if (false === strpos($url, basename(PHP_SELF))) {
			// 去掉网站地址、路径
			$url = ltrimStr($url, UE::site());
			$url = ltrimStr($url, UE::context());
			$url = trim($url, '/');
			
			if (!empty($url) && UE_Config::get('encode_url') && 'q_' == $url[0].$url[1]) {
				$url = UE_Encoder::decode($url);
			}
			
			// 把Rewrite风格当前字符串为$app/$ctl/$act[/$id/x/$x?xx=$xx&...]
			// 转成 $app/$ctl/$act[/$id/x/$x&xx=$xx&...]			
			// 去掉伪静态后缀		
			$queryString = str_replace(UE_Config::get('rewrite_ext').'?', '&', $url);  // .html? => &
			$queryString = rtrimStr($queryString, UE_Config::get('rewrite_ext'));      // .html => ''
						
			$queryString = str_replace('?', '&', $queryString);
		} else {
			if (!empty($url) && UE_Config::get('encode_url') && isset($_GET['q'])) {
				$queryString = UE_Encoder::decode($_GET['q']);
				unset($_GET['q']);
			} else {			
				// 取 ? 后面的字符串
				if (false !== $pos = strpos($url, '?')) {
					$queryString = substr($url, $pos+1);
				} else {
					$queryString = '';
				}
			}
		}
		
		if (!$queryString) {
			return $parseHistory[md5($url)] = array('app' => $defApp, 'ctl' => $defCtl, 'act' => $defAct, 'id' => $defId);
		}
			
		// 当前取得 app=$app&ctl=$ctl&act=$act[&....]||$app/$ctl/$act/$id[/xx/$xx?yy=$yy]||$app/$ctl/$act/$id[/xx/$xx?yy=$yy]		
		// 解析URL
		parse_str($queryString, $param);
		
		// 取得Clear Url 的app/ctl/act/id...
		foreach ($param as $actionString => $p) {
			if (!empty($actionString) && false !== $pos = strpos($actionString, '/')) {
				$appRuleKey = substr($actionString, 0, $pos);
				if (array_key_exists($appRuleKey, self::$_rules)) {
					$actionString = self::$_rules[$appRuleKey] . substr($actionString, $pos);
				}
				
				$explode = explode('/', $actionString);
				
				empty($param['app']) && ($param['app']  = !empty($explode[0]) ? $explode[0] : $defApp);
				empty($param['ctl']) && ($param['ctl']  = !empty($explode[1]) ? $explode[1] : $defCtl);
				empty($param['act']) && ($param['act']  = !empty($explode[2]) ? $explode[2] : $defAct);
				empty($param['id'])  && ($param['id']   = !empty($explode[3]) ? $explode[3] : $defId);
				
				if(isset($explode[4])) {
					for($i = 5; $i <= count($explode); $i += 2) {
						empty($param[$explode[$i-1]]) && $param[$explode[$i-1]] = isset($explode[$i]) ? $explode[$i] : '';
					}
				}
			}
		}
		
		return $urlToArr[md5($url)] = $param; 
	}

}
